/*************************************************************************
    > File Name: bmp.c
    >Author :Simon
	  > company: GDOU
    > Mail: lsy476941913@live.com
    > Created Time: 2017年03月5日 星期四 20时36分17秒
 ************************************************************************/
#include "show_bmp.h"
#include "lcd.h"
extern int fbfd;

static char *fbp = 0;
static int xres = 0;
static int yres = 0;
static int bits_per_pixel = 0;
int width, height;

int 
bitmap_format_convert(int width, int height, uint32_t * dst, char *src)
{
	int i = 0;
	int x = 0;
	int y = 0;
	for (y = 0, i = 0; y < height; y++)
		for (x = 0; x < width; x++, i += 3)
			dst[(height - 1 - y) * width + x] =
			    src[i] << 0 | src[i + 1] << 8 | src[i + 2] << 16;
	return 0;
}

void 
draw_point(char *fb_mem, int x, int y, uint32_t color)
{
	memcpy(fb_mem + (y * 800 + x) * 4, &color, sizeof(uint32_t));
}

void
draw_rect_fill(char *fb_mem, int x, int y, int width, int height,
	       uint32_t * bmp_src)
{
	int i = 0, j = 0;
	for (j = y; j < y + height; j++)
		for (i = x; i < x + width; i++) {
			draw_point(fb_mem, i, j, *bmp_src);
			bmp_src += 1;
		}
}

int 
show_bmp(char *path, int x, int y)
{
	FILE *fp;
	char *bmp_buf = NULL;
	uint32_t *bmp_buf_dst = NULL;
	char *buf = NULL;
	int flen = 0;
	int ret = -1;
	int total_length = 0;

	if (path == NULL) {
		printf("path Error,return\n");
		return -1;
	}

	fp = fopen(path, "rb");
	if (fp == NULL) {
		printf("load cursor file open failed\n");
		return -1;
	}
	/* 求解文件长度 */
	fseek(fp, 0, SEEK_SET);
	fseek(fp, 0, SEEK_END);
	flen = ftell(fp);

	/* 再移位到文件头部 */
	fseek(fp, 0, SEEK_SET);
	ret = fread(&FileHead, sizeof(BITMAPFILEHEADER), 1, fp);
	if (ret != 1) {
		printf("read header error!\n");
		fclose(fp);
		return (-2);
	}
	//检测是否是bmp图像
	if (memcmp(FileHead.cfType, "BM", 2) != 0) {
		printf("it's not a BMP file\n");
		fclose(fp);
		return (-3);
	}
	ret = fread((char *)&InfoHead, sizeof(BITMAPINFOHEADER), 1, fp);
	if (ret != 1) {
		printf("read infoheader error!\n");
		fclose(fp);
		return (-4);
	}
	width = InfoHead.ciWidth;
	height = InfoHead.ciHeight;
	bmp_buf = (char *)malloc(sizeof(char) * ((width * height * 3)));
	if (bmp_buf == NULL) {
		printf("load > malloc bmp out of memory!\n");
		return -1;
	}
	//printf("flen-54:%d  width*height*3:%d\n", flen - 54,
	 //      width * height * 3);
	//printf("FileHead.cfSize =%d byte\n", FileHead.cfSize);
	total_length = width * height * 3;

	//跳转的数据区
	fseek(fp, FileHead.cfoffBits, SEEK_SET);
//	printf(" FileHead.cfoffBits = %d\n", FileHead.cfoffBits);
//	printf(" InfoHead.ciBitCount = %d\n", InfoHead.ciBitCount);

	//每行字节数ttt
	buf = bmp_buf;
	int padding = (4 - (width * 3) % 4) % 4;
	int line_size = width * 3;
	while ((ret = fread(buf,1,line_size,fp)) >= 0){
		if (ret == line_size){
			fseek(fp, padding, SEEK_CUR);
		}
		if (ret == 0){
			usleep(100);
			continue ;
		}
		buf += ret;
		total_length = total_length-line_size;
		if (total_length == 0) {
			break ;
		}
	}




	///重新计算，很重要！！
	total_length = width * height;
	bmp_buf_dst = (uint32_t *) malloc(sizeof(uint32_t) * (width * height));
	if (bmp_buf_dst == NULL) {
		printf("load > malloc bmp out of memory!\n");
		return -1;
	}
	bitmap_format_convert(width, height, bmp_buf_dst, bmp_buf);
	draw_rect_fill(fbp, x, y, width, height, bmp_buf_dst);
	free(bmp_buf);
	free(bmp_buf_dst);
	fclose(fp);
	return 0;
}

int 
show_bmp_picture(int fd, char *path,int x,int y)
{
	struct fb_var_screeninfo vinfo;
	struct fb_fix_screeninfo finfo;
	long int screensize = 0;

	//struct fb_bitfield red;
	//struct fb_bitfield green;
	//struct fb_bitfield blue;

	if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo)) {
		printf("Error：reading FSCREENINFO.\n");
		return -1;
	}

	if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo)) {
		printf("Error: reading VSCREENINFO.\n");
		return -1;
	}

	xres = vinfo.xres;
	yres = vinfo.yres;
	bits_per_pixel = vinfo.bits_per_pixel;

	//计算屏幕的总大小（字节）
	screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;

	//对象映射
	fbp =
	    (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
			 0);
	if (fbp == (char *)-1) {
		printf("Error: failed to map framebuffer device to memory.\n");
		return -1;
	}


	//显示图像
	show_bmp(path, x, y);
	//sleep(100);
	//删除对象映射
	munmap(fbp, screensize);

	return 0;
}



// static void
// fb_update(int fd,struct fb_var_screeninfo *vi)   //将要渲染的图形缓冲区的内容绘制到设备显示屏来
// {
//    vi->yoffset = 1;
//    ioctl(fd, FBIOPUT_VSCREENINFO, vi);
//    vi->yoffset = 0;
//    ioctl(fd, FBIOPUT_VSCREENINFO, vi);
// }
